package com.qining618.cms.ucenter.service.impl;

import com.qining618.cms.ucenter.domain.Third;
import com.qining618.cms.ucenter.domain.User;
import com.qining618.cms.ucenter.domain.UserAuth;
import com.qining618.cms.ucenter.enums.UserAuthTypeEnum;
import com.qining618.cms.ucenter.mapper.UserMapper;
import com.qining618.cms.ucenter.service.ThirdService;
import com.qining618.cms.ucenter.service.UserAuthService;
import com.qining618.cms.ucenter.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qining618.common.core.weixin.api.SnsAPI;
import com.qining618.common.core.weixin.bean.sns.Jscode2sessionResult;
import com.qining618.common.core.weixin.bean.wxa.WxaDPhoneInfo;
import com.qining618.common.core.weixin.util.WxaUtil;
import com.qining618.common.exception.BusinessException;
import com.qining618.common.result.ErrorCode;
import com.qining618.common.utils.NumberUtils;
import com.qining618.common.utils.StringUtils;
import com.qining618.common.utils.time.ClockUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author qining
 * @date 2019-09-16
 */
@Transactional(readOnly = true, rollbackFor = Exception.class)
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private ThirdService thirdService;
    @Autowired
    private UserAuthService userAuthService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User getByWechatMiniPhone(String code, String encryptedData, String iv, String ip) {
        Third third = thirdService.getWechatMiniInfo();
        if (third == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND,  "微信小程序信息不存在");
        }
        Jscode2sessionResult sessionResult = SnsAPI.jscode2session(third.getAppid(), third.getAppsecret(), code);
        if (!sessionResult.isSuccess()) {
            throw new BusinessException(ErrorCode.REMOTE_ERROR, "获取凭证失败！");
        }
        String sessionKey = sessionResult.getSession_key();

        WxaDPhoneInfo phoneInfo = WxaUtil.decrypPhoneInfo(sessionKey, encryptedData, iv);
        if (phoneInfo == null || StringUtils.isBlank(phoneInfo.getPhoneNumber())) {
            throw new BusinessException(ErrorCode.PARAM_IS_INVALID, "获取手机号失败！");
        }
        User user = this.baseMapper.getByMobile(phoneInfo.getPhoneNumber());
        if (user == null) {
            Date date = ClockUtil.currentDate();
            user = User.builder()
                    .nickname(StringUtils.hidePhone(phoneInfo.getPhoneNumber()))
                    .registerIp(ip)
                    .registerTime(date)
                    .registerIp(ip)
                    .isAdmin(false)
                    .build();
            user.init();
            int opNum = this.baseMapper.insert(user);
            if (opNum != 1) {
                throw new BusinessException(ErrorCode.DB_ERROR, "保存用户信息失败");
            }
        }
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User getByWechatMiniCode(String code, String ip) {
        Third third = thirdService.getWechatMiniInfo();
        if (third == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND,  "微信小程序信息不存在");
        }
        Jscode2sessionResult sessionResult = SnsAPI.jscode2session(third.getAppid(), third.getAppsecret(), code);
        if (!sessionResult.isSuccess()) {
            throw new BusinessException(ErrorCode.REMOTE_ERROR, "获取凭证信息失败");
        }
        // 根据openId检查用户是否存在
        UserAuth userAuth = userAuthService.getWechatMiniUserAuth(third.getAppid(), sessionResult.getOpenid());
        if (userAuth != null) {
            // 小程序授权用户信息存在 直接返回用户信息
            return this.baseMapper.selectById(userAuth.getUserId());
        }

        // 小程序授权信息不存在  unionid不为空 检验unionid用户是否存在
        User user = null;
        if (StringUtils.isNotBlank(sessionResult.getUnionid())) {
            UserAuth orgUserAuth = userAuthService.getWechatUnionidUserAuth(sessionResult.getUnionid());
            if (orgUserAuth != null) {
                user = this.baseMapper.selectById(orgUserAuth.getUserId());
            }
        }

        Date date = ClockUtil.currentDate();
        // 微信用户信息不存在，新建用户
        if (user == null) {
            user = User.builder()
                    .nickname("用户" + NumberUtils.randomNumber(1_000, 1_000_000))
                    .registerIp(ip)
                    .registerTime(date)
                    .isAdmin(false)
                    .build();
            user.init();
            int opNum = this.baseMapper.insert(user);
            if (opNum != 1) {
                throw new BusinessException(ErrorCode.DB_ERROR, "保存用户信息失败");
            }
        }

        // 保存小程序用户信息
        userAuth = new UserAuth();
        userAuth.setUserId(user.getId());
        userAuth.setType(UserAuthTypeEnum.WECHAT_MINI);
        userAuth.setAppid(third.getAppid());
        userAuth.setOpenid(sessionResult.getOpenid());
        userAuth.setUnionid(sessionResult.getUnionid());
        boolean result = this.userAuthService.save(userAuth);
        if (!result) {
            throw new BusinessException(ErrorCode.DB_ERROR, "保存授权信息失败");
        }
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String bindWechatMiniPhone(Long userId, String code, String encryptedData, String iv) {
        Third third = thirdService.getWechatMiniInfo();
        if (third == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND,  "微信小程序信息不存在");
        }
        Jscode2sessionResult sessionResult = SnsAPI.jscode2session(third.getAppid(), third.getAppsecret(), code);
        if (!sessionResult.isSuccess()) {
            throw new BusinessException(ErrorCode.REMOTE_ERROR, "获取凭证失败！");
        }
        String sessionKey = sessionResult.getSession_key();

        WxaDPhoneInfo phoneInfo = WxaUtil.decrypPhoneInfo(sessionKey, encryptedData, iv);
        if (phoneInfo == null || StringUtils.isBlank(phoneInfo.getPhoneNumber())) {
            throw new BusinessException(ErrorCode.PARAM_IS_INVALID, "获取手机号失败！");
        }

        boolean isExist = this.baseMapper.existByMobile(phoneInfo.getPhoneNumber());
        if (isExist) {
            throw new BusinessException(ErrorCode.MOBILE_CONFLICT, "手机号已存在", phoneInfo.getPhoneNumber());
        }

        User user = new User();
        user.setId(userId);
        user.setMobile(phoneInfo.getPhoneNumber());
        int opNum = this.baseMapper.updateById(user);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
        return user.getMobile();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateLoginSuccess(Long userId, String ip) {
        Date date = ClockUtil.currentDate();
        int opNum = this.baseMapper.updateLoginSuccess(userId, date, ip);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void resetPassword(Long id, String password) {
        User user = this.baseMapper.selectById(id);
        if (user == null || user.getIsAdmin()) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND);
        }

        User upUser = new User();
        upUser.setId(user.getId());
        upUser.setPassword(DigestUtils.md5Hex(password));
        int opNum = this.baseMapper.updateById(upUser);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void freeze(Long userId, Date dueTime, String reason) {
        User upUser = new User();
        upUser.setId(userId).setIsFreeze(true).setFreezeTime(new Date()).setFreezeDueTime(dueTime).setFreezeReason(reason);
        int opNum = this.baseMapper.updateById(upUser);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unFreeze(Long userId) {
        int opNum = this.baseMapper.unFreeze(userId);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void incTodayCommentTotal(Long userId) {
        int opNum = this.baseMapper.incTodayCommentTotal(userId, 1);
        if (opNum != 1) {
            throw new BusinessException(ErrorCode.DB_ERROR);
        }
    }
}
